//
// Parser.cpp for  in /home/jousse_f//workspace/C++/abstractVM
// 
// Made by florian jousseau
// Login   <jousse_f@epitech.net>
// 
// Started on  Mon Feb  6 12:17:31 2012 florian jousseau
// Last update Fri Apr 13 15:35:46 2012 florian jousseau
//

#include <iostream>
#include "Parser.hh"
#include "Exception.hh"

const std::string simple_instr[] =
  {
    "pop",
    "dump",
    "add",
    "sub",
    "mul",
    "div",
    "mod",
    "print",
    "exit",
    ""
  };

const std::string typage[] =
  {
    "int8",
    "int16",
    "int32",
    "float",
    "double",
    ""
  };

void	Parser::checkSimpleLine(const std::string & line)
{
  int		i = 0;

  if (line[0] == ';')
    throw AbstractEx("");
  else if (line == "")
    throw AbstractEx("");
  int	f = line.find(" ", 0);
  if (f != -1)
    throw AbstractEx("[Error] Command not found");
  if (line == "exit")
    this->exit += 1;
  while (simple_instr[i] != "")
    {
      if (line == simple_instr[i])
	return ;
      i++;
    }
  throw AbstractEx("[Error] Command not found");
}

void	      Parser::checkValue(std::string &line, int it)
{
  int	p1;
  int	p2;
  int	i = 0;
  std::string	tmp;

  this->Value = line.erase(0, it);
  this->nb = 1;
  p1 = this->Value.find("(");
  p2 = this->Value.find(")");
  if ((p1 == -1 || p2 == -1) || p1 >= p2 - 1)
    throw AbstractEx("[Error] The assembly program includes one or more lexical or syntactic errors");
  tmp = this->Value;
  this->Value = this->Value.erase(p1, this->Value.size());
  nbToCheck = tmp.erase(0, p1 + 1);
  nbToCheck = nbToCheck.erase(nbToCheck.size() - 1, nbToCheck.size());
  while (typage[i] != "")
    {
      if (i > 2)
	this->nb = 2;
      if (typage[i] == this->Value)
	return ;
      i++;
    }
  throw AbstractEx("[Error] Type unknown");
}

void	Parser::checkInt(const std::string &nb)
{
  int		it = 0;

  if (nb[0] == '-')
    it = 1;
  while (nb[it])
    {
      if (nb[it] > '9' || nb[it] < '0')
	throw AbstractEx("[Error] Wrong int format");
      it++;
    }
  this->N = nb;
}

void	Parser::checkOther(const std::string &nb)
{
  int		it = 0;
  int		pts = 0;

  if (nb[0] == '-')
    it = 1;
  while (nb[it])
    {
      if ((nb[it] > '9' || nb[it] < '0') && nb[it] != '.')
	throw AbstractEx("[Error] Wrong double/float format");
      if (nb[it] == '.')
	pts++;
      if (pts > 1)
	throw AbstractEx("[Error] Wrong double/flaot format");
      it++;
    }
  if (pts != 1)
    throw AbstractEx("[Error] Wrong double/flaot format");
  this->Z = nb;
}

void	Parser::checkNumber()
{
  if (this->nb != 2)
    checkInt(nbToCheck);
  else
    checkOther(nbToCheck);
}

void	Parser::initLine(const std::string &line)
{
  this->S = line;
  this->Instr = "";
  this->Value = "";
  this->N = "";
  this->Z = "";
  this->nb = 0;
  this->Catch = 0;
}

void	Parser::toParse(std::string & line)
{
  int	len = 0;

  initLine(line);
  try
    {
      if (!line.find("push ", 0))
	{
	  len = 5;
	  this->Instr = "push";
	}
      else if (!line.find("assert ", 0))
	{
	  len = 7;
	  this->Instr = "assert";
	}
      else
	{
	  checkSimpleLine(line);
	  this->Instr = line;
	  return ;
	}
      this->checkValue(line, len);
      this->checkNumber();
    }
  catch (AbstractEx& e)
    {
      this->Catch = 1;
      std::string	error = e.what();
      if (error != "")
  	std::cerr << e.what() << std::endl;
    }
}

Parser::Parser()
  :S(""), Instr(""), Value(""), N(""), Z(""), exit(0), nbToCheck(""), nb(0), Catch(0)
{

}

Parser::Parser(const Parser & other)
  :S(other.S), Instr(other.Instr), Value(other.Value), N(other.N), Z(other.Z), exit(other.exit), nbToCheck(other.nbToCheck), nb(other.nb), Catch(other.Catch)
{

}

Parser	&Parser::operator=(const Parser & other)
{
  if (this != &other)
    {
      this->S = other.getS();
      this->Instr = other.getInstr();
      this->Value = other.getValue();
      this->N = other.getN();
      this->Z = other.getZ();
      this->Catch = other.getCatch();
      this->exit = other.exit;
      this->nb = other.nb;
      this->nbToCheck = other.nbToCheck;
    }
  return (*this);
}

int		Parser::getCatch() const
{
  return (this->Catch);
}

int		Parser::getExit() const
{
  return (this->exit);
}

std::string	Parser::getS() const
{
  return this->S;
}

std::string	Parser::getInstr() const
{
  return this->Instr;
}

std::string	Parser::getValue() const
{
  return this->Value;
}

std::string	Parser::getN() const
{
  return this->N;
}

std::string	Parser::getZ() const
{
  return this->Z;
}

